using Microsoft.AspNetCore.Mvc.Filters;
using PowerManage.Service.UOW;

namespace PowerManage.API.UOW;

/// <summary>
/// 行为过滤器 :  工作单元过滤器
/// </summary>
public class UnitOfWorkFilterAttribute : ActionFilterAttribute
{
    private UnitOfWorkAttribute? _unitOfWorkAttribute;

    /// <summary>
    /// 在action方法执行前调用
    /// </summary>
    /// <param name="context"></param>
    public override void OnActionExecuting(ActionExecutingContext context)
    {
        // //从当前 HTTP 请求的服务容器中，根据类型 IUnitOfWork 获取一个服务实例，并将其转换为 UnitOfWork 类型 。也可以用泛型获取
        // var unitOfWork = context.HttpContext.RequestServices.GetService(typeof(IUnitOfWork)) as UnitOfWork;
        // //  开始事务
        // unitOfWork.BeginTransaction();

        //给全局事务添加开关
        //context.ActionDescriptor.EndpointMetadata：包含当前请求的 Action 方法上标注的所有 特性（Attribute）
        //.FirstOrDefault(...) 从这些元数据中找出第一个满足条件的对象 —— 即对象的类型是 UnitOfWorkAttribute
        //x.GetType() == typeof(UnitOfWorkAttribute) 只选中那些对象的类型是 UnitOfWorkAttribute 的项
        //as UnitOfWorkAttribute 将找到的对象尝试转换为 UnitOfWorkAttribute 类型。如果类型不匹配，不会抛异常，而是返回 null。
        // _unitOfWorkAttribute =
        //     context.ActionDescriptor.EndpointMetadata.FirstOrDefault(x => x.GetType() == typeof(UnitOfWorkAttribute)) as
        //         UnitOfWorkAttribute;

        //.OfType<UnitOfWorkAttribute>() 会自动筛选出所有该类型的对象，并进行类型转换。更简洁、安全，避免手动用 GetType() 和 as。
        _unitOfWorkAttribute = context.ActionDescriptor.EndpointMetadata
            .OfType<UnitOfWorkAttribute>()
            .FirstOrDefault();
        //  如果当前 Action 方法上标记了 [UnitOfWork] 特性，并且该特性的 IsTransactional 属性为 false，则跳过事务处理逻辑（即不开启事务）。
        if (_unitOfWorkAttribute != null && !_unitOfWorkAttribute.IsTransactional)
        {
            return;
        }

        var unitOfWork = context.HttpContext.RequestServices.GetService<IUnitOfWork>() as UnitOfWork;
        unitOfWork.BeginTransaction();
    }

    /// <summary>
    /// 在action方法执行后调用
    /// </summary>
    /// <param name="context"></param>
    public override void OnActionExecuted(ActionExecutedContext context)
    {
        // var unitOfWork = context.HttpContext.RequestServices.GetService<IUnitOfWork>() as UnitOfWork;
        // //  提交事务
        // unitOfWork.Commit();

        if (_unitOfWorkAttribute != null && !_unitOfWorkAttribute.IsTransactional)
        {
            return;
        }

        var unitOfWork = context.HttpContext.RequestServices.GetService<IUnitOfWork>() as UnitOfWork;
        unitOfWork.Commit();
    }
}